package com.example.user.customviewdemo.drawing.matrix;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

/**
 * Created by user on 2016/5/12.
 */
public class GestureImageView extends ImageView {
    private Matrix matrix;
    private Matrix curMatrix;

    public GestureImageView(Context context) {
        super(context);
    }
    public GestureImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        matrix = new Matrix();
        curMatrix = new Matrix();
        startPoint = new PointF();
        midPoint = new PointF();

        setScaleType(ScaleType.FIT_CENTER);
    }

    public GestureImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        matrix.set(getImageMatrix());
    }

    private float startDistance;//两手触碰时，刚按下时两点间的距离
    private PointF startPoint;//单点触碰时，刚按下时的坐标
    private PointF midPoint;//两手指触碰，刚按下时中心点坐标
    private int mode = 0;
    private final int DRAG = 1;//拖动模式
    private final int ZOOM = 2;//缩放模式

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        /**
         * 矩阵的所有变换都是相对于刚按下时的matrix变换操作
         * 而不是手指移动时上一个状态的matrix
         */
        int action = event.getActionMasked();
        switch (action){
            case MotionEvent.ACTION_DOWN:
                setScaleType(ScaleType.MATRIX);
                mode = DRAG;
                curMatrix.set(getImageMatrix());//记录手指单点触碰时刚按下的matrix
                startPoint.set(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mode = ZOOM;
                startDistance = getDistance(event);
                //避免一个手指，但是有两个触点
                if(startDistance > 10f){
                    midPoint = getMidPoint(event);
                    curMatrix.set(getImageMatrix());//记录手指多点触碰，刚按下时的matrix
                }
                matrix.set(curMatrix);
                break;
            case MotionEvent.ACTION_MOVE:
                switch (mode){
                    case DRAG:
                        float dx = event.getX() - startPoint.x;
                        float dy = event.getY() - startPoint.y;
                        //相对于手指单点触碰刚按下时的matrix
                        matrix.set(curMatrix);
                        matrix.preTranslate(dx,dy);
                        break;
                    case ZOOM:
                        float distance = getDistance(event);
                        if(distance > 10f) {
                            float scale = distance / startDistance;
                            //相对于手指多点触碰，刚按下时的matrix，中点为刚按下时两手直线的中点
                            matrix.set(curMatrix);
                            matrix.preScale(scale, scale, startPoint.x,startPoint.y);
                        }
                        break;
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mode = 0;
                break;
            case MotionEvent.ACTION_UP:
                mode = 0;
                break;
        }
        setImageMatrix(matrix);
        return true;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    /**
     *  获取两点距离
     * @param event
     * @return
     */
    private float getDistance(MotionEvent event){
        float x0 = event.getX(0);
        float x1 = event.getX(1);
        float y0 = event.getY(0);
        float y1 = event.getY(1);
        return (float) Math.sqrt((x0 - x1)*(x0 - x1) + (y0 - y1)*(y0 - y1));
    }


    /**
     * 获取两点间的中点坐标
     * @param event
     * @return
     */
    private PointF getMidPoint(MotionEvent event){
        float x0 = event.getX(0);
        float x1 = event.getX(1);
        float y0 = event.getY(0);
        float y1 = event.getY(1);
        PointF point = new PointF();
        point.set((x0 + x1)/2,(y0 + y1)/2);
        return point;
    }
}
